home *** CD-ROM | disk | FTP | other *** search
/ PC User 2003 January / Disc 1 / PCU0103CD1.iso / entertn / demos / files / aomtrial.exe / AOM / AI / SCN10P2.XS < prev    next >
Encoding:
Text File  |  2002-08-01  |  19.6 KB  |  651 lines

  1. //==============================================================================
  2. // Scn10p2: AI Scenario Script for scenario 10 player 2
  3. //==============================================================================
  4. /*
  5.    AI owner:  Mike Kidd
  6.    Scenario owner: Jeff Brown
  7.  
  8.    Overview:
  9.    The player needs to rescue Chiron, but must achieve a number of 
  10.    intermediate objectives.  First, he picks up a bunch of centaurs, then uses
  11.    them to kill prison guards to claim one area and get resources.  The player 
  12.    makes a few more units, then goes to capture first one part, then another, of 
  13.    the city.  Finally, the player can use siege to destroy the bandits' migdol
  14.    fortress.
  15.  
  16.    The AI has a few components.  A simple economic framework will keep villagers 
  17.    gathering in several zones of the map.  Triggers will spawn units and call a 
  18.    spawn() AI function, with parameters indicating that it should attack P1 units,
  19.    P1 buildings, or P8 (P1 ally) buildings using a pair of attack routes.
  20.  
  21.    Finally, when the player is about to start his assault on the fortress, the
  22.    CPAI will spawn one last set of defenders, which will be absorbed into a defend plan.
  23.  
  24.    The CPAI does no unit training and no upgrading, and very limited god power usage.
  25.  
  26.    Difficulty is adjusted through the size and timing of spawned unit groups.
  27.   
  28.    7/31/2002:  Added economic AI bits to keep gatherers busy.
  29.  
  30. */
  31. //==============================================================================
  32.  
  33.  
  34. include "scn lib.xs";
  35.  
  36. // Globals
  37. int         lastAttackPlanID = -1;        // Updated with plan ID as each attack is launched
  38.  
  39. int         startTime = -1;               // Updated with start time when cinematic is done.  In seconds.
  40. int         visionTime = -1;              // Updated by wakeup() function, time (in sec) to cast vision.
  41. int         age3Time = 720;               // OK to go to age 3 at 12 minutes
  42. int         age4Time = 1500;              // OK to go to age 4 at 25 minutes
  43. int         nextAttackTime = 300;
  44. int         attackInterval = 180;
  45. int         nextAttackSize = 3;
  46. int         attackSizeIncrement = 1;
  47.  
  48. int         siegeMaintainPlan = -1;
  49. int         mythMaintainPlan = -1;
  50. int         barracksUnitMaintainPlan = -1;
  51. int         barracksUnit = -1;
  52. int         chariotMaintainPlan = -1;
  53.  
  54. int         attackQuery = -1;             // Shared by all armies
  55. int         attackQuery2 = -1;            // Additional query for building targets
  56. int         attackQuery3 = -1;            // Additional query for player 3 buildings
  57.  
  58. int         gathererTypeID = -1;
  59. int         mainBase = -1;                // Used for gathering, centered north of TC
  60. int         woodBase = -1;                // Used for wood only, west of TC, centered on lumber camp.
  61.  
  62.  
  63. // Cinematic block markers
  64.  
  65. const string   cbRouteInnerA = "6438";
  66. const string   cbRouteInnerB = "6439";
  67. const string   cbRouteInnerC = "6440";
  68.  
  69. const string   cbRouteOuterA = "6441";
  70. const string   cbRouteOuterB = "6442";
  71. const string   cbRouteOuterC = "6443";
  72.  
  73. const string   cbTownCenter = "6444";
  74. const string   cbBase2 = "6450";
  75.  
  76.  
  77.  
  78.  
  79. int   routeInner = -1;
  80. int   routeOuter = -1;
  81.  
  82.  
  83. // *****************************************************************************
  84. //
  85. //                                FUNCTIONS
  86. //
  87. // *****************************************************************************
  88.  
  89.  
  90. int initMainBase(vector center=vector(-1,-1,-1), float radius = 50.0)
  91. {
  92.    int baseID = -1;
  93.    // Nuke bases, add one base to rule them all
  94.    kbBaseDestroyAll(cMyID);
  95.  
  96.    baseID = kbBaseCreate(cMyID, "Base "+kbBaseGetNextID(), center, radius);
  97.    if (baseID < 0)
  98.       aiEcho("***** Main base creation failed. *****");
  99.  
  100.    vector baseFront=xsVectorNormalize(kbGetMapCenter()-center);     // Set front
  101.    kbBaseSetFrontVector(cMyID, mainBase, baseFront);                 
  102.    kbBaseSetMaximumResourceDistance(cMyID, baseID, radius+20.0);                    // Gather up to 20m beyond base perimeter
  103.    kbBaseSetMain(cMyID, baseID, true);     // Make this the main base
  104.  
  105.    // Add the buildings
  106.    int buildingQuery = -1;
  107.    int count = 0;
  108.    buildingQuery = kbUnitQueryCreate("Building Query");     // All buildings in the base
  109.    configQuery(buildingQuery, cUnitTypeBuilding, -1, cUnitStateAliveOrBuilding, cMyID, center, false, radius);
  110.    kbUnitQueryResetResults(buildingQuery);
  111.    count = kbUnitQueryExecute(buildingQuery);
  112.  
  113.    int i = 0;
  114.    int buildingID = -1;
  115.    for (i=0; < count)
  116.    {
  117.       buildingID = kbUnitQueryGetResult(buildingQuery, i);
  118.       // Add it to the base
  119.       kbBaseAddUnit( cMyID, baseID, buildingID );
  120.    }
  121.    return(baseID);
  122. }
  123.  
  124.  
  125.  
  126. int makeBase(vector center=vector(-1,-1,-1), float radius = 50.0)
  127. {
  128.    int baseID = -1;
  129.  
  130.    baseID = kbBaseCreate(cMyID, "Base "+kbBaseGetNextID(), center, radius);
  131.    if (baseID < 0)
  132.       aiEcho("***** Base creation failed. *****");
  133.  
  134.    vector baseFront=xsVectorNormalize(kbGetMapCenter()-center);     // Set front
  135.    kbBaseSetFrontVector(cMyID, mainBase, baseFront);                 
  136.    kbBaseSetMaximumResourceDistance(cMyID, baseID, radius+20.0);                    // Gather up to 20m beyond base perimeter
  137.  
  138.    // Add the buildings
  139.    int buildingQuery = -1;
  140.    int count = 0;
  141.    buildingQuery = kbUnitQueryCreate("Base Query");     // All buildings in the base
  142.    configQuery(buildingQuery, cUnitTypeBuilding, -1, cUnitStateAliveOrBuilding, cMyID, center, false, radius);
  143.    kbUnitQueryResetResults(buildingQuery);
  144.    count = kbUnitQueryExecute(buildingQuery);
  145.  
  146.    int i = 0;
  147.    int buildingID = -1;
  148.    for (i=0; < count)
  149.    {
  150.       buildingID = kbUnitQueryGetResult(buildingQuery, i);
  151.       // Add it to the base
  152.       kbBaseAddUnit( cMyID, baseID, buildingID );
  153.    }
  154.    return(baseID);
  155. }
  156.  
  157.  
  158. void initEcon()
  159. {
  160.    aiSetAttackResponseDistance(20.0);   // Kill escrows
  161.    kbEscrowSetPercentage( cEconomyEscrowID, cAllResources, 0.0);
  162.    kbEscrowSetPercentage( cMilitaryEscrowID, cAllResources, 0.0);
  163.    kbEscrowAllocateCurrentResources();
  164.  
  165.    aiSetAutoGatherEscrowID(cRootEscrowID);
  166.    aiSetAutoFarmEscrowID(cRootEscrowID);
  167.    gathererTypeID = kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionGatherer,0);
  168.  
  169.    
  170.    int herdPlanID=aiPlanCreate("GatherHerdable Plan", cPlanHerd);
  171.    if (herdPlanID >= 0)
  172.    {
  173.       aiPlanAddUnitType(herdPlanID, cUnitTypeHerdable, 0, 100, 100);
  174.       aiPlanSetVariableInt(herdPlanID, cHerdPlanBuildingTypeID, 0, cUnitTypeSettlementLevel1);
  175.       aiPlanSetActive(herdPlanID);
  176.    }
  177.  
  178.    aiSetResourceGathererPercentageWeight(cRGPScript, 1);
  179.    aiSetResourceGathererPercentageWeight(cRGPCost, 0);
  180.  
  181.    kbSetAICostWeight(cResourceFood, 1.0);
  182.    kbSetAICostWeight(cResourceWood, 0.7);
  183.    kbSetAICostWeight(cResourceGold, 0.8);
  184.    kbSetAICostWeight(cResourceFavor, 7.0);
  185.  
  186.    aiSetResourceGathererPercentage(cResourceFood, 7.0/11.0, false, cRGPScript);
  187.    aiSetResourceGathererPercentage(cResourceWood, 3.0/11.0, false, cRGPScript);
  188.    aiSetResourceGathererPercentage(cResourceGold, 1.0/11.0, false, cRGPScript);
  189.    aiSetResourceGathererPercentage(cResourceFavor, 0.0, false, cRGPScript);
  190.    aiNormalizeResourceGathererPercentages(cRGPScript);
  191.  
  192.    //bool aiSetResourceBreakdown( int resourceTypeID, int resourceSubTypeID, int numberPlans, int planPriority, float percentage, int baseID )
  193. //    aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeEasy, numFoodEasyPlans, 50, 1.0, gMainBaseID);
  194. //   aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeHuntAggressive, numFoodHuntAggressivePlans, 100, 1.0, gMainBaseID);
  195.    aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeFarm, 1, 50, 1.0, mainBase);
  196.    aiSetResourceBreakdown(cResourceWood, cAIResourceSubTypeEasy, 1, 50, 1.0, woodBase);
  197.     aiSetResourceBreakdown(cResourceGold, cAIResourceSubTypeEasy, 1, 50, 1.0, mainBase);
  198. //   aiSetResourceBreakdown(cResourceFavor, cAIResourceSubTypeEasy, numFavorPlans, 50, 1.0, gMainBaseID);
  199.  
  200.    // Create villager maintain plan
  201.    createSimpleMaintainPlan(gathererTypeID, 11, true, mainBase);
  202. }
  203.  
  204.  
  205.  
  206.  
  207. // Called by a trigger, to let AI know that it's time to start maintain plans, etc.
  208. void defend(int parm=-1)
  209. {
  210.    // Init low-priority defend plan to manage hoplites
  211.    int defendPlan =aiPlanCreate("Defend Plan", cPlanDefend);
  212.    if (defendPlan >= 0)
  213.    {
  214.       aiPlanAddUnitType(defendPlan, cUnitTypeMilitary, 0, 200, 200);    // All unassigned mil units
  215.       aiPlanSetDesiredPriority(defendPlan, 10);                       // Way low, below scouting and attack
  216.       aiPlanSetVariableVector(defendPlan, cDefendPlanDefendPoint, 0, kbGetBlockPosition(cbTownCenter));
  217.       aiPlanSetVariableFloat(defendPlan, cDefendPlanEngageRange, 0, 60);
  218.       aiPlanSetVariableBool(defendPlan, cDefendPlanPatrol, 0, false);
  219.       aiPlanSetVariableFloat(defendPlan, cDefendPlanGatherDistance, 0, 20.0);
  220.       aiPlanSetInitialPosition(defendPlan, kbGetBlockPosition(cbTownCenter));
  221.       aiPlanSetUnitStance(defendPlan, cUnitStanceDefensive);
  222.  
  223.       aiPlanSetVariableInt(defendPlan, cDefendPlanRefreshFrequency, 0, 5);
  224.       aiPlanSetNumberVariableValues(defendPlan, cDefendPlanAttackTypeID, 2, true);
  225.       aiPlanSetVariableInt(defendPlan, cDefendPlanAttackTypeID, 0, cUnitTypeUnit);
  226.       aiPlanSetVariableInt(defendPlan, cDefendPlanAttackTypeID, 1, cUnitTypeBuilding);
  227.  
  228.       aiPlanSetActive(defendPlan); 
  229.       aiEcho("Creating defend plan");
  230.    }
  231. }
  232.  
  233.  
  234. // Called by a trigger
  235. void serpents(int parm=-1)
  236. {
  237.       xsEnableRule("useSerpents");
  238. }
  239.  
  240.  
  241. void age2EventHandler(int bogus=-1)
  242. {
  243.  
  244. }
  245.  
  246. void age3EventHandler(int bogus=-1)
  247. {
  248.  
  249. }
  250.  
  251.  
  252. void age4EventHandler(int bogus=-1)
  253. {
  254.  
  255. }
  256.  
  257.  
  258.     
  259.  
  260.  
  261.  
  262. void attack(int player = -1)
  263. {
  264.    int qty = -1;
  265.    qty = getUnassignedUnitCount(kbGetBlockPosition(cbTownCenter), 50.0, cMyID, cUnitTypeMilitary);
  266.    if (qty < 1)
  267.       return;
  268.  
  269.    int   attackID=aiPlanCreate("Attack "+timeString()+"  ", cPlanAttack);
  270.    if (attackID < 0)
  271.    {
  272.       return;
  273.    }
  274.  
  275.    if (aiPlanSetVariableInt(attackID, cAttackPlanPlayerID, 0, player) == false)
  276.    {
  277.       return;
  278.    }
  279.  
  280.    if (aiPlanSetNumberVariableValues(attackID, cAttackPlanTargetTypeID, 2, true) == false)
  281.    {
  282.       return;
  283.    }
  284.  
  285. // aiPlanSetVariableInt(attackID, cAttackPlanQueryID, 0, attackQuery);
  286.  
  287.    // add "unit" and "building" to attack list
  288.    aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit);
  289.    aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding);
  290.  
  291.    if (aiRandInt(2) > 0)
  292.       aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, routeInner);
  293.    else
  294.       aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, routeOuter);
  295.  
  296.    aiPlanSetVariableInt(attackID, cAttackPlanLastRefreshTime, 0, 30);
  297.  
  298.    aiPlanSetVariableVector(attackID, cAttackPlanGatherPoint, 0, kbGetBlockPosition(cbTownCenter));
  299.    aiPlanSetVariableFloat(attackID, cAttackPlanGatherDistance, 0, 15.0);
  300.  
  301.    aiPlanAddUnitType(attackID, cUnitTypeMilitary, 0, qty, qty);
  302.  
  303.  
  304.    aiPlanSetInitialPosition(attackID, kbGetBlockPosition(cbTownCenter));
  305.    aiPlanSetRequiresAllNeedUnits(attackID, true);
  306.    aiPlanSetActive(attackID);
  307.    aiEcho("Activating attack plan "+attackID+" with "+qty+" units.");
  308. }
  309.  
  310.  
  311.  
  312. void spawn(int parm = -1)
  313. {
  314.    aiEcho("Spawn fired with parm "+parm);
  315.    if (parm == 0)
  316.       attack(1);
  317.    if (parm == 1)
  318.       attack(8);
  319.    if (parm == 2)
  320.       attack(1);
  321. }
  322.  
  323.  
  324.  
  325.  
  326.  
  327.  
  328. void main()
  329. {
  330.    aiEcho("Starting Scn10p2.xs");
  331.    kbSetTownLocation(kbGetBlockPosition(cbTownCenter));
  332.  
  333.    //Calculate some areas.
  334.    kbAreaCalculate(1200.0);
  335.  
  336.    aiRandSetSeed();
  337.  
  338.    mainBase = initMainBase(kbGetBlockPosition(cbTownCenter), 60.0);
  339.    woodBase = makeBase(kbGetBlockPosition(cbBase2), 20.0);
  340.    initEcon();
  341.  
  342.    aiSetAgeEventHandler(cAge2, "age2EventHandler");
  343.    aiSetAgeEventHandler(cAge3, "age3EventHandler");
  344.    aiSetAgeEventHandler(cAge4, "age4EventHandler");
  345.  
  346.    routeInner = attackRoute("Inner Attack Route",cbRouteInnerA, cbRouteInnerB, cbRouteInnerC);
  347.    routeOuter = attackRoute("Outer Attack Route",cbRouteOuterA, cbRouteOuterB, cbRouteOuterC);
  348.  
  349. }
  350.  
  351.  
  352.  
  353.  
  354.  
  355.  
  356.  
  357. // *****************************************************************************
  358. //
  359. // RULES
  360. //
  361. // *****************************************************************************
  362.  
  363.  
  364. rule goToAge3
  365.    inactive
  366.    mininterval 20
  367. {
  368.    if ( (xsGetTime()/1000) < age3Time )
  369.       return;
  370.    researchTech(cTechAge3Nephthys);
  371.    xsEnableRule("goToAge4");
  372.    xsEnableRule("getAge3UnitUpgrades");
  373.    xsEnableRule("getAge3ArmoryUpgrades");
  374.    xsDisableSelf();
  375. }
  376.  
  377. rule goToAge4
  378.    inactive
  379.    mininterval 20
  380. {
  381.    if ( (xsGetTime()/1000) < age4Time )
  382.       return;
  383.    researchTech(cTechAge4Horus);
  384.    xsEnableRule("getAge4UnitUpgrades");
  385.    xsEnableRule("getAge4ArmoryUpgrades");
  386.    xsDisableSelf();
  387. }
  388.  
  389.  
  390.  
  391. rule getAge2UnitUpgrades
  392.    inactive
  393.    minInterval 20
  394. {
  395.    if ( (xsGetTime()/1000) < (startTime + startTime + age3Time)/3 )
  396.       return;     // Wait till 1/3 to age3
  397.    researchTech(cTechMediumAxemen);
  398.    researchTech(cTechMediumSlingers);
  399.    researchTech(cTechMediumSpearmen);
  400.    xsDisableSelf();
  401. }
  402.  
  403. rule getAge2ArmoryUpgrades
  404.    inactive
  405.    minInterval 20
  406. {
  407.    if ( (xsGetTime()/1000) < (startTime + age3Time + age3Time)/3 )
  408.       return;     // Wait till 2/3 to age3
  409.    aiEcho("Getting age 2 armory upgrades");
  410.    researchTech(cTechCopperWeapons);
  411.    researchTech(cTechCopperMail);
  412.    researchTech(cTechCopperShields);
  413.    xsDisableSelf();
  414. }
  415.  
  416. rule getAge3UnitUpgrades
  417.    inactive
  418.    minInterval 20
  419. {
  420.    if ( (xsGetTime()/1000) < (age3Time+300) )
  421.       return;
  422.    researchTech(cTechHeavyAxemen);
  423.    researchTech(cTechHeavySlingers);
  424.    researchTech(cTechHeavySpearmen);
  425.    researchTech(cTechHeavyChariots);
  426.    xsDisableSelf();
  427. }
  428.  
  429. rule getAge3ArmoryUpgrades
  430.    inactive
  431.    minInterval 20
  432. {
  433.    if ( (xsGetTime()/1000) < (age3Time+300) )
  434.       return;
  435.    researchTech(cTechBronzeWeapons);
  436.    researchTech(cTechBronzeMail);
  437.    researchTech(cTechBronzeShields);
  438.    xsDisableSelf();
  439. }
  440.  
  441. rule getAge4UnitUpgrades
  442.    inactive
  443.    minInterval 20
  444. {
  445.    if ( (xsGetTime()/1000) < (age4Time+600) )
  446.       return;
  447.    researchTech(cTechChampionAxemen);
  448.    researchTech(cTechChampionSlingers);
  449.    researchTech(cTechChampionSpearmen);
  450.    researchTech(cTechChampionChariots);
  451.    xsDisableSelf();
  452. }
  453.  
  454. rule getAge4ArmoryUpgrades
  455.    inactive
  456.    minInterval 20
  457. {
  458.    if ( (xsGetTime()/1000) < (age4Time+300) )
  459.       return;
  460.    researchTech(cTechIronWeapons);
  461.    researchTech(cTechIronMail);
  462.    researchTech(cTechIronShields);
  463.    xsDisableSelf();
  464. }
  465.  
  466.  
  467.  
  468. rule scout
  469.    inactive
  470. {
  471.    // just set up an explore plan
  472.    int exploreID = aiPlanCreate("Explore", cPlanExplore);
  473.    if(exploreID >= 0)
  474.    {
  475.       //aiPlanAddVariableFloat( exploreID, cExplorePlanLOSMultiplier, "LOS Multiplier", 1);
  476.       aiPlanSetVariableFloat( exploreID, cExplorePlanLOSMultiplier,  0, 4.0 );
  477.       aiPlanAddUnitType(exploreID, cUnitTypeSpearman, 1, 1, 1);
  478.       aiPlanSetActive(exploreID);
  479.    }
  480.    xsDisableSelf();
  481. }
  482.  
  483.  
  484. /* Sample
  485. rule attackGenerator
  486.    minInterval 10
  487.    active
  488. {
  489.    //aiEcho("attack check running, next time is "+nextAttackTime);
  490.    if ( (xsGetTime()/1000) < nextAttackTime )
  491.       return;
  492.  
  493.    testAttack();
  494.    nextAttackTime = (xsGetTime()/1000) + attackInterval;
  495.    attackSize = attackSize + attackSizeIncrement;
  496.    aiEcho("Next attack size will be "+attackSize+".");
  497. }
  498. */
  499.  
  500.  
  501.  
  502. rule useVision       // When it's time, cast vision at one of four markers.
  503.    minInterval 5
  504.    inactive
  505. {
  506. /*
  507.  
  508.  
  509.    if (visionTime < 0)
  510.       return;
  511.  
  512.    int rand = aiRandInt(4);
  513.    switch (rand)
  514.    {
  515.    case 0:
  516.       {
  517.          aiCastGodPowerAtPosition(cTechVision, kbGetBlockPosition(cbVision0));
  518.          break;
  519.       }
  520.    case 1:
  521.       {
  522.          aiCastGodPowerAtPosition(cTechVision, kbGetBlockPosition(cbVision1));
  523.          break;
  524.       }
  525.    case 2:
  526.       {
  527.          aiCastGodPowerAtPosition(cTechVision, kbGetBlockPosition(cbVision2));
  528.          break;
  529.       }
  530.    case 3:
  531.       {
  532.          aiCastGodPowerAtPosition(cTechVision, kbGetBlockPosition(cbVision3));
  533.          break;
  534.       }
  535.    }
  536.    aiEcho("Vision has been used");
  537.    */
  538.    xsDisableSelf();
  539. }
  540.  
  541.  
  542.  
  543. rule useSerpents // Same logic as lightning, look for enemy military units
  544.    minInterval 5
  545.    inactive
  546. {
  547.  
  548.    // look for a group of 7 enemy units, at the Migdol location or at my main army's location
  549.    int targetUnit = -1;
  550.  
  551.    static int tempQuery = -1;
  552.    if (tempQuery < 0)
  553.    {  // Doesn't exist, set it up
  554.       tempQuery = kbUnitQueryCreate("useSerpents1");
  555.       if ( configQuery(tempQuery, cUnitTypeUnit, -1, cUnitStateAlive, 1, kbGetBlockPosition(cbTownCenter), true, 75) == false)
  556.          return;
  557.    }
  558.    kbUnitQueryResetResults(tempQuery);
  559.    int targetCount = kbUnitQueryExecute(tempQuery); 
  560.  
  561.    if (targetCount < 7)
  562.    {
  563.       if (lastAttackPlanID < 0)
  564.          return;
  565.       vector pVec = aiPlanGetLocation(lastAttackPlanID);
  566.       if (xsVectorGetX(pVec)>=0)
  567.       {
  568.          static int tempQuery2 = -1;
  569.          if (tempQuery2 < 0)
  570.          {  // Doesn't exist, set it up
  571.             tempQuery2 = kbUnitQueryCreate("useSerpents2");
  572.             if ( configQuery(tempQuery2, cUnitTypeMilitary, -1, cUnitStateAlive, 1, pVec, true, 50) == false)
  573.                return;
  574.          }
  575.          else
  576.             kbUnitQuerySetPosition(tempQuery, pVec); // Because pVec changes as army moves
  577.          kbUnitQueryResetResults(tempQuery2);
  578.          targetCount = kbUnitQueryExecute(tempQuery2); 
  579.          if (targetCount < 7)
  580.             return;
  581.          else
  582.             targetUnit = kbUnitQueryGetResult(tempQuery2, 0);  // grab first unit
  583.       }
  584.    } 
  585.    else
  586.       targetUnit = kbUnitQueryGetResult(tempQuery, targetCount/2);  // grab middle unit
  587.  
  588.  
  589.    aiEcho("Using Plague of Serpents at "+kbUnitGetPosition(targetUnit));
  590.    if ( aiCastGodPowerAtPosition(cTechSerpents, kbUnitGetPosition(targetUnit)) == true)
  591.       xsDisableSelf();
  592.    else
  593.       aiEcho("Serpents failed at "+kbUnitGetPosition(targetUnit));
  594. }
  595.  
  596.  
  597. rule useAncestors // Same logic as Serpents, look for enemy military units
  598.    minInterval 5
  599.    inactive
  600. {
  601.  
  602.    // look for a group of 7 enemy units, at the Migdol location or at my main army's location
  603.    int targetUnit = -1;
  604.  
  605.    static int tempQuery = -1;
  606.    if (tempQuery < 0)
  607.    {  // Doesn't exist, set it up
  608.       tempQuery = kbUnitQueryCreate("useAncestors1");
  609.       if ( configQuery(tempQuery, cUnitTypeUnit, -1, cUnitStateAlive, 1, kbGetBlockPosition(cbTownCenter), true, 75) == false)
  610.          return;
  611.    }
  612.    kbUnitQueryResetResults(tempQuery);
  613.    int targetCount = kbUnitQueryExecute(tempQuery); 
  614.  
  615.    if (targetCount < 7)
  616.    {
  617.       vector pVec = aiPlanGetLocation(lastAttackPlanID);
  618.       if (xsVectorGetX(pVec)>=0)
  619.       {
  620.          static int tempQuery2 = -1;
  621.          if (tempQuery2 < 0)
  622.          {  // Doesn't exist, set it up
  623.             tempQuery2 = kbUnitQueryCreate("useAncestors2");
  624.             if ( configQuery(tempQuery, cUnitTypeMilitary, -1, cUnitStateAlive, 1, pVec, true, 50) == false)
  625.                return;
  626.          }
  627.          kbUnitQueryResetResults(tempQuery2);
  628.          targetCount = kbUnitQueryExecute(tempQuery2); 
  629.          if (targetCount < 7)
  630.             return;
  631.          else
  632.             targetUnit = kbUnitQueryGetResult(tempQuery2, 0);  // grab first unit
  633.       }
  634.       else
  635.          return;  // No army to check
  636.    } 
  637.    else//SkeletonPower//PharaohRespawnCityoftheDead
  638.       targetUnit = kbUnitQueryGetResult(tempQuery, targetCount/2);  // grab middle unit
  639.  
  640.  
  641.    aiEcho("Using Ancestors");
  642.    if ( aiCastGodPowerAtPosition(cTechSkeletonPower, kbUnitGetPosition(targetUnit)) == true)
  643.       xsDisableSelf();
  644.    else
  645.       aiEcho("Ancestors failed at "+kbUnitGetPosition(targetUnit));
  646.  
  647. }
  648.  
  649.  
  650.  
  651.